import { Inject, Injectable } from '@nestjs/common';
import { Response } from 'express';
import { ResultData } from 'src/common/utils/result';
import { ListToTree } from 'src/common/utils/index';
import { ExportTable } from 'src/common/utils/export';

import { CacheEnum, DataScopeEnum } from 'src/common/enum/index';
import { MenuService } from '../menu/menu.service';
import { CreateRoleDto, UpdateRoleDto, ListRoleDto, ChangeStatusDto } from './dto/index';
import { PrismaService } from '@/module/common/prisma/prisma.service';
import { Prisma, Role } from '@prisma/client';
import { pick } from 'lodash';
import { pickEquals, pickLike } from '@/common/utils/prisma';
import { PrismaConst } from '@/common/constant/prisma.constant';
import { CacheEvict } from '@/common/decorators/redis.decorator';
@Injectable()
export class RoleService {
    constructor(
        private readonly menuService: MenuService,
        private readonly prisma: PrismaService
    ) { }
    @CacheEvict(CacheEnum.SYS_USER_KEY, '*')
    async create(createRoleDto: CreateRoleDto) {
        const role = await this.prisma.role.create({ data: pickEquals(createRoleDto, PrismaConst.role) });

        // 创建角色与菜单的关联
        const roleMenuRelations = createRoleDto.menuIds.map((menuId) => {
            return {
                roleId: role.roleId,
                menuId,
            };
        });

        await this.prisma.roleMenu.createMany({ data: roleMenuRelations });
        return ResultData.ok(role);
    }

    async findAll(query: ListRoleDto) {
        let where: any = {
            delFlag: '0',
            ...pickEquals(query, ['roleId', 'status']),
            ...pickLike(query, ['roleName', 'roleKey']),
        }

        if (query?.beginTime && query?.endTime) {
            where.createTime = {
                gte: new Date(query.beginTime),
                lte: new Date(query.endTime)
            };
        }
        let skip = void 0
        let take = void 0
        if (query.pageSize && query.pageNum) {
            skip = (query.pageNum - 1) * query.pageSize;
            take = +query.pageSize;
        }

        const [list, total] = await Promise.all([
            this.prisma.role.findMany({
                where,
                skip,
                take
            }),
            this.prisma.role.count({ where, }),
        ])
        return ResultData.ok({
            list,
            total,
        });
    }

    async findOne(roleId: number) {
        const res = await this.prisma.role.findUnique({
            where: {
                roleId,
                delFlag: '0',
            },
        });
        return ResultData.ok(res);
    }
    async update(updateRoleDto: UpdateRoleDto) {
        const hasId = await this.prisma.roleMenu.findFirst({
            where: {
                roleId: updateRoleDto.roleId,
            },
            select: {
                roleId: true,
            },
        });

        //角色已关联菜单
        if (hasId) {
            await this.prisma.roleMenu.deleteMany({
                where: {
                    roleId: updateRoleDto.roleId,
                },
            });
        }
        const roleMenuRelations = updateRoleDto.menuIds.map((menuId) => {
            return {
                roleId: updateRoleDto.roleId,
                menuId: menuId,
            };
        });

        await this.prisma.roleMenu.createMany({
            data: roleMenuRelations,
        });


        // 更新角色信息
        const res = await this.prisma.role.update({
            where: {
                roleId: updateRoleDto.roleId,
            },
            data: pickEquals(updateRoleDto, PrismaConst.role),
        });
        return ResultData.ok(res);
    }

    async dataScope(updateRoleDto: UpdateRoleDto) {
        const hasPermission = await this.prisma.roleDept.findFirst({
            where: {
                roleId: updateRoleDto.roleId,
            },
            select: {
                roleId: true,
            },
        });
        // 角色已有权限 或者 非自定义权限 先删除权限关联
        if (hasPermission || updateRoleDto.dataScope !== DataScopeEnum.DATA_SCOPE_CUSTOM) {
            await this.prisma.roleDept.deleteMany({
                where: {
                    roleId: updateRoleDto.roleId,
                },
            });
        }
        // 插入新的权限关联
        const roleDeptRelations = updateRoleDto.deptIds.map((deptId) => {
            return {
                roleId: updateRoleDto.roleId,
                deptId: deptId,
            };
        });
        await this.prisma.roleDept.createMany({
            data: roleDeptRelations,
        });
        // 更新角色信息
        const updatedRole = await this.prisma.role.update({
            where: {
                roleId: updateRoleDto.roleId,
            },
            data: pickEquals(updateRoleDto, PrismaConst.role),
        });
        return ResultData.ok(updatedRole);
    }

    async changeStatus(changeStatusDto: ChangeStatusDto) {
        const res = await this.prisma.role.update({
            where: {
                roleId: changeStatusDto.roleId,
            },
            data: {
                status: changeStatusDto.status,
            }
        })
        return ResultData.ok(res);
    }
    @CacheEvict(CacheEnum.SYS_USER_KEY, '*')
    async remove(roleIds: number[]) {
        const data = await this.prisma.role.updateMany({
            where: {
                roleId: { in: roleIds },
            },
            data: {
                delFlag: '1',
            }
        })
        await this.prisma.userRole.deleteMany({
            where: {
                roleId: { in: roleIds },
            },
        });
        return ResultData.ok(data);
    }

    async deptTree(roleId: number) {
        const res = await this.prisma.dept.findMany({
            where: {
                delFlag: '0',
            },
        });
        const tree = ListToTree(
            res,
            (m) => +m.deptId,
            (m) => m.deptName,
        );
        const deptIds = await this.prisma.roleDept.findMany({
            where: { roleId },
            select: {
                deptId: true
            },
        });
        const checkedKeys = deptIds.map((item) => {
            return item.deptId;
        });
        return ResultData.ok({
            depts: tree,
            checkedKeys: checkedKeys,
        });
    }

    async findRoles(where: Prisma.RoleFindManyArgs) {
        return await this.prisma.role.findMany(where);
    }
    /**
     * 根据角色获取用户权限列表
     */
    async getPermissionsByRoleIds(roleIds: number[]) {
        if (roleIds.includes(1)) return [{ perms: '*:*:*' }]; //当角色为超级管理员时，开放所有权限
        const list = await this.prisma.roleMenu.findMany({
            where: {
                roleId: { in: roleIds },
            },
            select: {
                menuId: true
            },
        });

        const menuIds = list.map((item) => item.menuId);
        const permission = await this.menuService.findMany({
            where: { delFlag: '0', status: '0', menuId: { in: menuIds } },
        });
        return permission;
    }

    /**
     * 根据角色ID异步查找与之关联的部门ID列表。
     *
     * @param roleId - 角色的ID，用于查询与该角色关联的部门。
     * @returns 返回一个Promise，该Promise解析为一个部门ID的数组。
     */
    async findRoleWithDeptIds(roleId: number) {
        // 使用TypeORM的实体仓库查询方法，异步查找与指定角色ID相关联的部门ID。
        const res = await this.prisma.roleDept.findMany({
            where: {
                roleId
            },
            select: {
                deptId: true,
            },
        });
        // 将查询结果映射为仅包含部门ID的数组并返回。
        return res.map((item) => item.deptId);
    }

    /**
     * 导出角色管理数据为xlsx
     * @param res
     */
    async export(res: Response, body: ListRoleDto) {
        delete body.pageNum;
        delete body.pageSize;
        const list = await this.findAll(body);
        const options = {
            sheetName: '角色数据',
            data: list.data.list,
            header: [
                { title: '角色编号', dataIndex: 'roleId' },
                { title: '角色名称', dataIndex: 'roleName', width: 15 },
                { title: '权限字符', dataIndex: 'roleKey' },
                { title: '显示顺序', dataIndex: 'roleSort' },
                { title: '状态', dataIndex: 'status' },
                { title: '创建时间', dataIndex: 'createTime', width: 15 },
            ],
        };
        ExportTable(options, res);
    }
}
